<template>
  <div style="width: 100%; height: 100%; display: flex; justify-content: space-between">
    <div style="width: calc(100% - 321px); height: 100%; overflow-y: auto">
      <div style="width: 100%; height: 48px; border-bottom: 1px solid #dcdcec; background-color: #fcfcfc">
        <el-button @click="onSave">保存</el-button>
      </div>
      <div style="width: 100%; height: calc(100% - 48px); display: flex">
        <div style="height: 100%; width: 50px; background-color: #fcfcfc">
          <el-tooltip effect="dark" content="设置" placement="right-start">
            <div style="background-color: #c2bf05; border-radius: 5px; cursor: pointer; vertical-align: middle">
              <el-icon><Tools /></el-icon>
            </div>
          </el-tooltip>
        </div>
        <div style="height: 100%; width: calc(100% - 50px)" id="containerBox">
          <div id="container" style="width: 100%; height: 100%"></div>
          <TeleportContainer />
        </div>
      </div>
    </div>
    <div style="width: 320px; height: 100%; border-left: 1px solid #dcdcdc"></div>
  </div>
</template>
<script setup lang="ts">
import { onMounted } from 'vue';
import TableNode from './nodes/table-node.vue';
import { Graph } from '@antv/x6';
import { register, getTeleport } from '@antv/x6-vue-shape';
import { Transform } from '@antv/x6-plugin-transform';
import { Selection } from '@antv/x6-plugin-selection';
import { Snapline } from '@antv/x6-plugin-snapline';
import { Keyboard } from '@antv/x6-plugin-keyboard';
import { Clipboard } from '@antv/x6-plugin-clipboard';
import { History } from '@antv/x6-plugin-history';
import type { Cell, Edge } from '@antv/x6';

defineOptions({
  name: 'PhysicalDiagram',
});
const data: { cells: Cell.Properties[] } = {
  cells: [
    {
      position: { x: 80, y: 40 },
      size: { width: 1250, height: 500 },
      attrs: {
        text: { text: '群组' },
        body: { fill: '#fffbe6', stroke: '#ffe7ba' },
        label: { refY: 16, fontSize: 16 },
      },
      visible: true,
      shape: 'rect',
      id: '8f1c893b-2b75-48ee-8f0f-35df9ad7d1ab',
      zIndex: 1,
      children: ['10803299-7159-41b8-82f5-5e602e289e3d', '558813d8-a42d-4173-b9c8-d3745917d55c'],
    },
    {
      position: { x: 249.9999999999999, y: 90 },
      size: { width: 320, height: 368 },
      view: 'vue-shape-view',
      shape: 'custom-table-node',
      ports: {
        groups: {
          top: {
            position: 'top',
            attrs: {
              circle: {
                r: 4,
                magnet: true,
                stroke: '#5F95FF',
                strokeWidth: 1,
                fill: '#fff',
                style: { visibility: 'hidden' },
              },
            },
          },
          right: {
            position: 'right',
            attrs: {
              circle: {
                r: 4,
                magnet: true,
                stroke: '#5F95FF',
                strokeWidth: 1,
                fill: '#fff',
                style: { visibility: 'hidden' },
              },
            },
          },
          bottom: {
            position: 'bottom',
            attrs: {
              circle: {
                r: 4,
                magnet: true,
                stroke: '#5F95FF',
                strokeWidth: 1,
                fill: '#fff',
                style: { visibility: 'hidden' },
              },
            },
          },
          left: {
            position: 'left',
            attrs: {
              circle: {
                r: 4,
                magnet: true,
                stroke: '#5F95FF',
                strokeWidth: 1,
                fill: '#fff',
                style: { visibility: 'hidden' },
              },
            },
          },
        },
        items: [
          { group: 'top', id: 'c0dfcf22-4c21-48cb-8d04-772b5d4309f0' },
          { group: 'right', id: 'd334485f-4ac1-467b-957f-3a1eec697953' },
          { group: 'bottom', id: '07f01a15-0a1f-4f74-8150-2e371c1634a4' },
          { group: 'left', id: '6992341b-9c06-4398-b732-67ac98a6d0e5' },
        ],
      },
      id: '10803299-7159-41b8-82f5-5e602e289e3d',
      zIndex: 10,
      parent: '8f1c893b-2b75-48ee-8f0f-35df9ad7d1ab',
      data: { tableName: 'SYS_USER' },
    },
    {
      position: { x: 890, y: 106 },
      size: { width: 320, height: 368 },
      view: 'vue-shape-view',
      shape: 'custom-table-node',
      ports: {
        groups: {
          top: {
            position: 'top',
            attrs: {
              circle: {
                r: 4,
                magnet: true,
                stroke: '#5F95FF',
                strokeWidth: 1,
                fill: '#fff',
                style: { visibility: 'hidden' },
              },
            },
          },
          right: {
            position: 'right',
            attrs: {
              circle: {
                r: 4,
                magnet: true,
                stroke: '#5F95FF',
                strokeWidth: 1,
                fill: '#fff',
                style: { visibility: 'hidden' },
              },
            },
          },
          bottom: {
            position: 'bottom',
            attrs: {
              circle: {
                r: 4,
                magnet: true,
                stroke: '#5F95FF',
                strokeWidth: 1,
                fill: '#fff',
                style: { visibility: 'hidden' },
              },
            },
          },
          left: {
            position: 'left',
            attrs: {
              circle: {
                r: 4,
                magnet: true,
                stroke: '#5F95FF',
                strokeWidth: 1,
                fill: '#fff',
                style: { visibility: 'hidden' },
              },
            },
          },
        },
        items: [
          { group: 'top', id: '97a20a02-c752-4249-a80a-f552f4fafefb' },
          { group: 'right', id: '86674f77-6575-4af5-8a2e-b19dbe304095' },
          { group: 'bottom', id: '139ed021-dc02-4335-9c85-43a2d6b23429' },
          { group: 'left', id: 'b8437ef0-8a27-45a1-8e8f-f0b3e4732153' },
        ],
      },
      id: '558813d8-a42d-4173-b9c8-d3745917d55c',
      zIndex: 10,
      tools: { items: [{ name: 'button-remove', args: { x: 2, y: 2 } }] },
      parent: '8f1c893b-2b75-48ee-8f0f-35df9ad7d1ab',
      data: { tableName: 'SYS_USER' },
    },
    {
      shape: 'dag-edge',
      attrs: { line: { strokeDasharray: '' } },
      id: '9ef8e815-79e2-4000-b1f9-8fb7e8ed4ee5',
      labels: [{ attrs: { line: { stroke: '#73d13d' }, text: { text: '左连接' } } }],
      zIndex: 12,
      source: {
        cell: '10803299-7159-41b8-82f5-5e602e289e3d',
        port: 'd334485f-4ac1-467b-957f-3a1eec697953',
      },
      target: {
        cell: '558813d8-a42d-4173-b9c8-d3745917d55c',
        port: 'b8437ef0-8a27-45a1-8e8f-f0b3e4732153',
      },
    },
  ],
};
const TeleportContainer = getTeleport();

const ports = {
  groups: {
    top: {
      position: 'top',
      attrs: {
        circle: {
          r: 4,
          magnet: true,
          stroke: '#5F95FF',
          strokeWidth: 1,
          fill: '#fff',
          style: {
            visibility: 'hidden',
          },
        },
      },
    },
    right: {
      position: 'right',
      attrs: {
        circle: {
          r: 4,
          magnet: true,
          stroke: '#5F95FF',
          strokeWidth: 1,
          fill: '#fff',
          style: {
            visibility: 'hidden',
          },
        },
      },
    },
    bottom: {
      position: 'bottom',
      attrs: {
        circle: {
          r: 4,
          magnet: true,
          stroke: '#5F95FF',
          strokeWidth: 1,
          fill: '#fff',
          style: {
            visibility: 'hidden',
          },
        },
      },
    },
    left: {
      position: 'left',
      attrs: {
        circle: {
          r: 4,
          magnet: true,
          stroke: '#5F95FF',
          strokeWidth: 1,
          fill: '#fff',
          style: {
            visibility: 'hidden',
          },
        },
      },
    },
  },
  items: [
    {
      group: 'top',
    },
    {
      group: 'right',
    },
    {
      group: 'bottom',
    },
    {
      group: 'left',
    },
  ],
};

register({
  shape: 'custom-table-node',
  width: 320,
  height: 368,
  component: TableNode,
  ports: {
    ...ports,
  },
});

Graph.registerEdge(
  'dag-edge',
  {
    inherit: 'edge',
    attrs: {
      line: {
        stroke: '#a0a0a0',
        strokeWidth: 1,
      },
    },
  },
  true,
);
let _graph: Graph | undefined;
onMounted(() => {
  const graph: Graph = new Graph({
    container: document.getElementById('container')!,
    grid: true,
    mousewheel: {
      enabled: true,
      zoomAtMousePosition: true,
      modifiers: 'ctrl',
      minScale: 0.5,
      maxScale: 3,
    },
    connecting: {
      router: 'manhattan',
      connector: {
        name: 'rounded',
        args: {
          radius: 8,
        },
      },
      anchor: 'center',
      connectionPoint: 'anchor',
      allowBlank: false,
      snap: {
        radius: 20,
      },
      createEdge() {
        return graph.createEdge({
          shape: 'dag-edge',
          labels: [
            {
              attrs: {
                line: {
                  stroke: '#73d13d',
                },
                text: {
                  text: '左连接',
                },
              },
            },
          ],
          attrs: {
            line: {
              strokeDasharray: '5 5',
            },
          },
          zIndex: 12,
        });
      },
    },
    highlighting: {
      magnetAdsorbed: {
        name: 'stroke',
        args: {
          attrs: {
            fill: '#5F95FF',
            stroke: '#5F95FF',
          },
        },
      },
    },
  });
  _graph = graph;

  // #region 使用插件
  graph
    .use(
      new Transform({
        resizing: true,
        rotating: true,
      }),
    )
    .use(
      new Selection({
        rubberband: true,
        showNodeSelectionBox: true,
      }),
    )
    .use(new Snapline())
    .use(new Keyboard())
    .use(new Clipboard())
    .use(new History());
  // #endregion

  // #region 快捷键与事件
  graph.bindKey(['meta+c', 'ctrl+c'], () => {
    const cells = graph.getSelectedCells();
    if (cells.length) {
      graph.copy(cells);
    }
    return false;
  });
  graph.bindKey(['meta+x', 'ctrl+x'], () => {
    const cells = graph.getSelectedCells();
    if (cells.length) {
      graph.cut(cells);
    }
    return false;
  });
  graph.bindKey(['meta+v', 'ctrl+v'], () => {
    if (!graph.isClipboardEmpty()) {
      const cells = graph.paste({ offset: 32 });
      graph.cleanSelection();
      graph.select(cells);
    }
    return false;
  });

  // undo redo
  graph.bindKey(['meta+z', 'ctrl+z'], () => {
    if (graph.canUndo()) {
      graph.undo();
    }
    return false;
  });
  graph.bindKey(['meta+shift+z', 'ctrl+shift+z'], () => {
    if (graph.canRedo()) {
      graph.redo();
    }
    return false;
  });

  // select all
  graph.bindKey(['meta+a', 'ctrl+a'], () => {
    const nodes = graph.getNodes();
    if (nodes) {
      graph.select(nodes);
    }
  });

  // delete
  graph.bindKey('delete', () => {
    const cells = graph.getSelectedCells();
    if (cells.length) {
      graph.removeCells(cells);
    }
  });

  // zoom
  graph.bindKey(['ctrl+1', 'meta+1'], () => {
    const zoom = graph.zoom();
    if (zoom < 1.5) {
      graph.zoom(0.1);
    }
  });
  graph.bindKey(['ctrl+2', 'meta+2'], () => {
    const zoom = graph.zoom();
    if (zoom > 0.5) {
      graph.zoom(-0.1);
    }
  });

  // 控制连接桩显示/隐藏
  const showPorts = (ports: NodeListOf<SVGElement>, show: boolean) => {
    for (let i = 0, len = ports.length; i < len; i += 1) {
      ports[i].style.visibility = show ? 'visible' : 'hidden';
    }
  };
  graph.on('node:mouseenter', () => {
    const container = document.getElementById('container')!;
    const ports = container.querySelectorAll('.x6-port-body') as NodeListOf<SVGElement>;
    showPorts(ports, true);
  });
  graph.on('node:mouseleave', () => {
    const container = document.getElementById('container')!;
    const ports = container.querySelectorAll('.x6-port-body') as NodeListOf<SVGElement>;
    showPorts(ports, false);
  });

  graph.on('edge:connected', ({ edge }: { edge: Edge }) => {
    edge.attr({
      line: {
        strokeDasharray: '',
      },
    });
  });

  // graph.on('node:change:size', ({ node }: { node: Node }) => {
  //   if (node) {
  //     console.log(node.getSize())
  //   }
  // })

  graph.on('edge:click', ({ edge }: { edge: Edge }) => {
    if (edge.attrs && edge.attrs.line?.stroke == '#409eff') {
      edge.attr({
        line: {
          stroke: '#a0a0a0',
          strokeWidth: 1,
        },
      });
    } else {
      edge.attr({
        line: {
          stroke: '#409eff',
          strokeWidth: 2,
        },
      });
    }
  });
  // #endregion
  const parent = graph.addNode({
    x: 40,
    y: 40,
    width: 900,
    height: 500,
    zIndex: 1,
    label: '群组',
    attrs: {
      label: {
        refY: 16,
        fontSize: 16,
      },
      body: {
        fill: '#fffbe6',
        stroke: '#ffe7ba',
      },
    },
  });
  const child1 = graph.addNode({
    shape: 'custom-table-node',
    x: 10,
    y: 60,
    zIndex: 10,
  });
  const child2 = graph.addNode({
    shape: 'custom-table-node',
    x: 280,
    y: 60,
    zIndex: 10,
    tools: [
      {
        name: 'button-remove', // 工具名称
        args: {
          // 工具对应的参数
          x: 2,
          y: 2,
        },
      },
    ],
  });
  parent.addChild(child1);
  parent.addChild(child2);
  loadData(data);
});
const onSave = () => {
  if (_graph) {
    const data: { cells: Cell.Properties[] } = _graph.toJSON();
    console.log(JSON.stringify(data));
  }
};
const loadData = (data: { cells: Cell.Properties[] }) => {
  if (_graph) {
    _graph.fromJSON(data);
  }
};
</script>
<style lang="scss">
.x6-widget-transform {
  margin: -1px 0 0 -1px;
  padding: 0px;
  border: 1px solid #239edd;
}
.x6-widget-transform > div {
  border: 1px solid #239edd;
}
.x6-widget-transform > div:hover {
  background-color: #3dafe4;
}
.x6-widget-transform-active-handle {
  background-color: #3dafe4;
}
.x6-widget-transform-resize {
  border-radius: 0;
}
// .x6-widget-transform-cursor-ne {
//   cursor: ne-resize;
// }
.x6-widget-selection-inner {
  border: 1px solid #239edd;
}
.x6-widget-selection-box {
  opacity: 0;
}
</style>
